<?php

  require_once "JooS/Helper/Abstract.php";
  require_once "Zend/Loader.php";

  final class JooS_Helper_Broker {
    const HELPER_INTERFACE = "JooS_Helper_Interface";

    const HELPER_SUBJECT_INTERFACE = "JooS_Helper_Subject";

    private $_helpers = array();

    private $_subject = null;

    private static $_helperBroker = null;

    private static $_loadedHelpers = array();

    private static $_paths = array(array(
      "dir" => "JooSX/", 
      "prefix" => "JooSX_"
    ));

    public static function addPrefix($prefix) {
      $prefix = rtrim($prefix, '_') . "_";
      $path = str_replace('_', DIRECTORY_SEPARATOR, $prefix);

      self::$_paths[] = array(
        "dir" => $path, 
        "prefix" => $prefix
      );
    }

    public static function helperBroker() {
      if (self::$_helperBroker === null)
        self::$_helperBroker = new self();

      return self::$_helperBroker;
    }

    public static function newInstance($subject) {
      if ($subject instanceof JooS_Helper_Subject) {
        $newInstance = new self();
        $newInstance->_subject = $subject;

        return $newInstance;
      }
      else
        self::throwException("Subject must implement ".self::HELPER_SUBJECT_INTERFACE);
    }

    public function __call($helper, $argv) {
      self::_getHelperReflection($helper);
    }

    public function __get($helper) {
      if (!$this->__isset($helper))
        self::throwException("Helper '$helper' was not found");
    
      return $this->_helpers[$helper];
    }

    public function __isset($helper) {
      $has = true;
      try {
        $this->_getHelper($helper);
      }
      catch (JooS_Helper_Exception $e) {
        $has = false;
      }
      return $has;
    }

    private function __construct($subject = null) {
      $this->Helper_Broker_InitPrefixesHelper();
    }

    private function _getHelper($helper) {
      if (!isset($this->_helpers[$helper])) {
        $this->_helpers[$helper] = self::_getHelperReflection($helper)->newInstance();
        $this->_helpers[$helper]->setSubject($this->_subject);
      }
      return $this->_helpers[$helper];
    }

    private static function _getHelperReflection($helper) {
      if (!isset(self::$_loadedHelpers[$helper])) {
        $className = null;
        for ($i=sizeof(self::$_paths) - 1; $i>=0; $i--) {
          try {
            $className = self::$_paths[$i]["prefix"] . $helper;
            @Zend_Loader::loadClass($className);
            break;
          }
          catch (Zend_Exception $e) {
            $className = null;
          }
        }
        if (is_null($className))
          self::throwException("Helper '$helper' was not found");

        $r_Helper = new ReflectionClass($className);
        if ($r_Helper->implementsInterface(self::HELPER_INTERFACE)) {
          self::$_loadedHelpers[$helper] = $r_Helper;
          $r_Helper->getMethod("init")->invoke(null);
        }
        else
          self::throwException("Helper '$helper' must implement ".self::HELPER_INTERFACE);
      }
      return self::$_loadedHelpers[$helper];
    }

    private static function throwException($message, $code = 0) {
      require_once "JooS/Helper/Exception.php";

      throw new JooS_Helper_Exception($message, $code);
    }
  }

?>